#include <stdlib.h>
#include <typeinfo>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"
#include "Valeur.h"


////////////////////////////////////////////////////////////////////////////////
// NoeudProg
////////////////////////////////////////////////////////////////////////////////

NoeudProg::NoeudProg(Noeud* seqDecl, Noeud* seqInst) {
    this->seqDecl = seqDecl;
    this->seqInst = seqInst;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudProg::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(1);
        seqDecl->getValeur();
        seqInst->getValeur();
        return valeur; // par convention, resultat = valeur de la derniere instruction
    }
    catch (char const*) {
        cout << "Une erreur est parvenu durant l'execution du programme "<< endl;
        throw;
    }
}


void NoeudProg::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudProg(this);
            seqDecl->Accept(visitor); // on affiche les fils en augmentant l'indentation
            seqInst->Accept(visitor); // on affiche les fils en augmentant l'indentation
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
	    visitor.VisitNoeudProg(this);
	    visitor.IncresIndentation();
	    visitor.afficherLigne();
	    visitor.afficherMotsCles("// Les Declarations ");
	    visitor.afficherLigne();
            seqDecl->Accept(visitor); // on affiche les fils en augmentant l'indentation
	    visitor.afficherLigne();
	    visitor.afficherMotsCles("// Les Instructions ");
	    visitor.afficherLigne();
            seqInst->Accept(visitor); // on affiche les fils en augmentant l'indentation
    	    visitor.afficherMotsCles("return 0;");
	    visitor.DecresIndentation();
	    visitor.afficherLigne();
	    visitor.afficherMotsCles("}");
	    visitor.afficherLigne();
        }
        else {
            seqDecl->Accept(visitor); // on affiche les fils en augmentant l'indentation
            seqInst->Accept(visitor); // on affiche les fils en augmentant l'indentation
            visitor.VisitNoeudProg(this);
        }
        if (typeid(visitor) == typeid(TypeVisitor) && visitor.getErreur() > 0) {
            cout << "Il y a (au moins) " << visitor.getErreur() << " dans ce programme " << endl;
            throw "erreur type";
        }
    }
    catch (char const*) {
        throw;
    }
}



////////////////////////////////////////////////////////////////////////////////
// NoeudSeqDecl
////////////////////////////////////////////////////////////////////////////////

NoeudSeqDecl::NoeudSeqDecl() : tabDecl() {
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudSeqDecl::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(1);
        for (unsigned int i=0; i<tabDecl.size(); i++)
            valeur = tabDecl[i]->getValeur();  // on evalue chaque declaration de la séquence
        return valeur; // par convention, resultat = valeur de la derniere declaration
    }
    catch (char const*) {
        throw;
    }
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqDecl::getSize() { 
    return tabDecl.size();
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqDecl::ajouteDecl(Noeud* declaration) {
    tabDecl.push_back(declaration);
}

void NoeudSeqDecl::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudSeqDecl(this);
            for (unsigned int i=0; i<tabDecl.size(); i++)
                tabDecl[i]->Accept(visitor); // on affiche les fils en augmentant l'indentation
            visitor.DecresIndentation();
        }
	else if (typeid(visitor) == typeid(ConversionVisitor)) {
	    visitor.VisitNoeudSeqDecl(this);
	    visitor.afficherLigne();
            for (unsigned int i=0; i<tabDecl.size(); i++)
                tabDecl[i]->Accept(visitor);
        }
        else {
            for (unsigned int i=0; i<tabDecl.size(); i++)
                tabDecl[i]->Accept(visitor);
            visitor.VisitNoeudSeqDecl(this);
        }
    }
    catch (char const*) {
        throw;
    }
}



////////////////////////////////////////////////////////////////////////////////
// NoeudDeclaration
////////////////////////////////////////////////////////////////////////////////

NoeudDeclaration::NoeudDeclaration(Noeud* variable, string type) {
    this->variable=variable;
    this->type=type;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudDeclaration::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(1);
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}

void NoeudDeclaration::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudDeclaration(this);
            this->variable->Accept(visitor);
            visitor.DecresIndentation();
        }
	else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  visitor.VisitNoeudDeclaration(this);
	    visitor.afficherType(this->type);
	    visitor.afficherMotsCles(" ");
            this->variable->Accept(visitor);
	    visitor.afficherMotsCles(";");
	    visitor.afficherLigne();
        }
        else {
            this->variable->Accept(visitor);
            visitor.VisitNoeudDeclaration(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}




////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudSeqInst::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(1);
        for (unsigned int i=0; i<tabInst.size(); i++)
            valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
        return valeur; // par convention, resultat = valeur de la derniere instruction
    }
    catch (char const*) {
        throw;
    }
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqInst::getSize() { // accesseur
    return tabInst.size();
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
    tabInst.push_back(instruction);
}

void NoeudSeqInst::Accept (NoeudVisitor& visitor) {
    if (typeid(visitor) == typeid(AfficherVisitor)) {
        visitor.IncresIndentation();
        visitor.VisitNoeudSeqInst(this);
        try {
            for (unsigned int i=0; i<tabInst.size(); i++)
                tabInst[i]->Accept(visitor); // on affiche les fils en augmentant l'indentation
        }
        catch (char const*) {
            throw;
        }
        visitor.DecresIndentation();
    }
    else if (typeid(visitor) == typeid(ConversionVisitor)) {
	    visitor.VisitNoeudSeqInst(this);
	    visitor.afficherLigne();
            for (unsigned int i=0; i<tabInst.size(); i++)
                tabInst[i]->Accept(visitor);
        }
    else {
        try {
            for (unsigned int i=0; i<tabInst.size(); i++)
                tabInst[i]->Accept(visitor);
        }
        catch (char const*) {
            throw;
        }
        visitor.VisitNoeudSeqInst(this);
    }
}





////////////////////////////////////////////////////////////////////////////////
// NoeudSi
////////////////////////////////////////////////////////////////////////////////

NoeudSi::NoeudSi(Noeud* expbool, Noeud* seqInst, Noeud* siSuivant) {
    this->expBool=expbool;
    this->seqInst=seqInst;
    this->siSuivant=siSuivant;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudSi::getValeur() {
    try {
        Valeur* valeur  = new ValeurInt(0); //
        if (((ValeurInt*)expBool->getValeur())->getValeur() == 1) valeur = seqInst->getValeur();
        else if (siSuivant != NULL) siSuivant->getValeur();
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}
void NoeudSi::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudSi(this);
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            if (siSuivant != NULL)
                siSuivant->Accept(visitor);
            visitor.DecresIndentation();
        }
	else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  NoeudSi* ns = this;
	  bool siPasse = false;
	 while (ns != NULL) {
	    if (!(siPasse)) {
	      visitor.afficherMotsCles("if (");
	      siPasse = true;
	    }
	    else
	      visitor.afficherMotsCles("else if (");
	    ns->expBool->Accept(visitor);
	    visitor.afficherMotsCles(")");
	    visitor.afficherMotsCles(" {");
	    visitor.afficherLigne();
	    visitor.IncresIndentation();
            ns->seqInst->Accept(visitor);
	    visitor.DecresIndentation();
	    visitor.afficherLigne();
	    visitor.afficherMotsCles("}");
	    visitor.afficherLigne();
	    ns = ((NoeudSi*)ns->siSuivant);
	  } 
        }
        else {
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.VisitNoeudSi(this);
            if (siSuivant != NULL)
                siSuivant->Accept(visitor);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}



////////////////////////////////////////////////////////////////////////////////
// NoeudPour
////////////////////////////////////////////////////////////////////////////////

NoeudPour::NoeudPour(Noeud* aff, Noeud* affDroite, Noeud* expbool, Noeud* seqInst) {
    this->expBool=expbool;
    this->seqInst=seqInst;
    this->aff=aff;
    this->affDroite=affDroite;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudPour::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(0); // =
        for (aff->getValeur();((ValeurInt*)expBool->getValeur())->getValeur(); affDroite->getValeur())
            valeur = seqInst->getValeur();
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}

void NoeudPour::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudPour(this);
            aff->Accept(visitor);
            expBool->Accept(visitor);
            affDroite->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
            visitor.VisitNoeudPour(this);
            aff->Accept(visitor);
            visitor.afficherMotsCles(";");
            expBool->Accept(visitor);
            visitor.afficherMotsCles(";");
            affDroite->Accept(visitor);
            visitor.afficherMotsCles(")");
	    visitor.afficherLigne();
            visitor.afficherMotsCles("{");
	    visitor.afficherLigne();
            visitor.IncresIndentation();
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
	    visitor.afficherLigne();
            visitor.afficherMotsCles("}");
	    visitor.afficherLigne();
        }
        else {
            aff->Accept(visitor);
            expBool->Accept(visitor);
            affDroite->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.VisitNoeudPour(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}



////////////////////////////////////////////////////////////////////////////////
// NoeudTantQue
////////////////////////////////////////////////////////////////////////////////

NoeudTantQue::NoeudTantQue(Noeud* expbool, Noeud* seqInst) {
    this->expBool=expbool;
    this->seqInst=seqInst;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudTantQue::getValeur() {
    try {
        Valeur* valeur = new ValeurInt(0); // =
        while (((ValeurInt*)expBool->getValeur())->getValeur() == 1) {
            valeur = seqInst->getValeur();
        }
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}


void NoeudTantQue::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudTantQue(this);
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
            visitor.VisitNoeudTantQue(this);
            expBool->Accept(visitor);
            visitor.afficherMotsCles(")");
	    visitor.afficherLigne();
            visitor.afficherMotsCles("{");
	    visitor.afficherLigne();
            visitor.IncresIndentation();
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
	    visitor.afficherLigne();
            visitor.afficherMotsCles("}");
	    visitor.afficherLigne();
        }
        else {
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.VisitNoeudTantQue(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}


////////////////////////////////////////////////////////////////////////////////
// NoeudRepeter
////////////////////////////////////////////////////////////////////////////////

NoeudRepeter::NoeudRepeter(Noeud* expbool, Noeud* seqInst) {
    this->expBool=expbool;
    this->seqInst=seqInst;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudRepeter::getValeur() {
    try {
        Valeur* valeur;
        do {
            valeur = seqInst->getValeur();
        }
        while (!((ValeurInt*)expBool->getValeur())->getValeur());
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}

void NoeudRepeter::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudRepeter(this);
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
            visitor.afficherMotsCles("do {");
	    visitor.IncresIndentation();
	    visitor.afficherLigne();
            seqInst->Accept(visitor);
            visitor.DecresIndentation();
            visitor.afficherMotsCles("} ");
            visitor.VisitNoeudRepeter(this);
            expBool->Accept(visitor);
            visitor.afficherMotsCles(");");
	    visitor.afficherLigne();
        }
        else {
            expBool->Accept(visitor);
            seqInst->Accept(visitor);
            visitor.VisitNoeudRepeter(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
    this->variable=variable;
    this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudAffectation::getValeur() {
    try {
        Valeur* valeur;
        valeur = expression->getValeur(); // on évalue l'expression
        ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}


void NoeudAffectation::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudAffectation(this);
            this->variable->Accept(visitor);
            this->expression->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  visitor.VisitNoeudAffectation(this);
            this->variable->Accept(visitor);
	    visitor.afficherMotsCles("=");
            this->expression->Accept(visitor);
	      visitor.afficherMotsCles(";");
	      visitor.afficherLigne();
        }
        else {
            this->variable->Accept(visitor);
            this->expression->Accept(visitor);
            visitor.VisitNoeudAffectation(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}

NoeudAffectationPour::NoeudAffectationPour(Noeud* variable, Noeud* expression) : NoeudAffectation(variable,expression) {
}


void NoeudAffectationPour::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudAffectation(this);
            this->variable->Accept(visitor);
            this->expression->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  visitor.VisitNoeudAffectation(this);
            this->variable->Accept(visitor);
	    visitor.afficherMotsCles("=");
            this->expression->Accept(visitor);
        }
        else {
            this->variable->Accept(visitor);
            this->expression->Accept(visitor);
            visitor.VisitNoeudAffectation(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}


////////////////////////////////////////////////////////////////////////////////
// NoeudLire
////////////////////////////////////////////////////////////////////////////////

NoeudLire::NoeudLire(Noeud* variable) {
    this->variable=variable;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudLire::getValeur() {
    Valeur* valeur = new ValeurInt(0);
    /* verifier le type de la variable, declarer une
    *  variable de se type. puis l'affecter a une Valeur**/
    if (((SymboleValue*)variable)->SymboleValue::getType() == ENTIER ) {
        int val;
        cin >> val;
        valeur = new ValeurInt(val);
    }
    else if (((SymboleValue*)variable)->SymboleValue::getType() == REEL) {
        float val;
        cin >> val;
        valeur = new ValeurFloat(val);
    }
    else if (((SymboleValue*)variable)->SymboleValue::getType() == CHAINE) {
        string val;
        cin >> val;
        string vaf = val;
        valeur = new ValeurString(vaf);
    }
    else if (((SymboleValue*)variable)->SymboleValue::getType() == CHAR) {
        char val, vc;
        cin >> vc;
        val = vc;
        valeur = new ValeurChar(val);
    }
    try {
        ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}

void NoeudLire::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudLire(this);
            variable->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  visitor.VisitNoeudLire(this);
            this->variable->Accept(visitor);
	    visitor.afficherMotsCles(";");
	    visitor.afficherLigne();
        }
        else {
            variable->Accept(visitor);
            visitor.VisitNoeudLire(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}

////////////////////////////////////////////////////////////////////////////////
// NoeudEcrire
////////////////////////////////////////////////////////////////////////////////

NoeudEcrire::NoeudEcrire(Noeud* expression) {
    this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
Valeur* NoeudEcrire::getValeur() {
    try {
        Valeur* valeur;
        if (typeid(*expression->getValeur()) == typeid(ValeurInt)) {
            cout << ((ValeurInt*)expression->getValeur())->getValeur();
        }

        if (typeid(*expression->getValeur()) == typeid(ValeurFloat)) {
            cout << ((ValeurFloat*)expression->getValeur())->getValeur();
        }
        if (typeid(*expression->getValeur()) == typeid(ValeurString)) { // on ecrie sans les guillement au extremité
            string chaine = ((ValeurString*)expression->getValeur())->getValeur();
            for (unsigned int i=0;i<chaine.size();i++) {
                if (chaine[i] == '\\' && chaine[i+1] == 'n') {
                    cout << endl; // caractere de saut de ligne
                    i++;
                }
                else if (chaine[i] == '\\' && chaine[i+1] == '\"') {
                    cout << '\"'; // on affiche ce qu'il u a derriere
                    i++;
                }
                else {
                    cout << chaine[i];
                }
            }

        }
        if (typeid(*expression->getValeur()) == typeid(ValeurChar)) {
            cout << ((ValeurChar*)expression->getValeur())->getValeur();
        }
        valeur = expression->getValeur(); // on évalue l'expression
        return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }
    catch (char const*) {
        throw;
    }
}


void NoeudEcrire::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudEcrire(this);
            expression->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
	  visitor.VisitNoeudEcrire(this);
            this->expression->Accept(visitor);
	    visitor.afficherMotsCles(";");
	    visitor.afficherLigne();
        }
        else {
            expression->Accept(visitor);
            visitor.VisitNoeudEcrire(this);
        }
    }
    catch (char const*) {
        visitor.IncresErreur();
    }
}



////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
        Noeud* operandeGauche,
        Noeud* operandeDroit) {
    this->operateur=operateur;
    this->operandeGauche=operandeGauche;
    this->operandeDroit=operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////
// J'ai pas eu le temps de mieux faire
Valeur* NoeudOperateurBinaire::getValeur() {
    Valeur* valeur =  new ValeurInt(0);
    Valeur* vog=operandeGauche->getValeur();
    Valeur* vod=operandeDroit->getValeur();

    if (typeid(*vod) == typeid(ValeurInt) && typeid(*vog) == typeid(ValeurInt)) {
        if      (this->operateur=="+") valeur = new ValeurInt((((ValeurInt*)vog)->getValeur())+(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="-") valeur = new ValeurInt((((ValeurInt*)vog)->getValeur())-(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="*") valeur = new ValeurInt((((ValeurInt*)vog)->getValeur())*(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="/") {
            try {
                if ((((ValeurInt*)vod)->getValeur())!=0 ||  (*(Symbole*)operandeDroit) == "<VARIABLE>" )
                    valeur = new ValeurInt((((ValeurInt*)vog)->getValeur())/(((ValeurInt*)vod)->getValeur()));
                else {
                    ErreurDiv(operandeDroit);
                }
            }
            catch (int) {
                throw;
            }
        }
    }
    else if (typeid(*vod) == typeid(ValeurInt) && typeid(*vog) == typeid(ValeurFloat)) {
        if      (this->operateur=="+") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())+(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="-") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())-(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="*") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())*(((ValeurInt*)vod)->getValeur()));
        else if (this->operateur=="/") {
            try {
                if ((((ValeurFloat*)vod)->getValeur())!=0 || (*(Symbole*)operandeDroit) == "<VARIABLE>" )
                    valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())/(float)(((ValeurInt*)vod)->getValeur()));
                else {
                    ErreurDiv(operandeDroit);
                }
            }
            catch (int) {
                throw;
            }
        }
    }
    else if (typeid(*vod) == typeid(ValeurFloat) && typeid(*vog) == typeid(ValeurFloat)) {
        if      (this->operateur=="+") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())+(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="-") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())-(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="*") valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())*(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="/") {
            try {
                if ((((ValeurFloat*)vod)->getValeur())!=0.0 || (*(Symbole*)operandeDroit) == "<VARIABLE>" )
                    valeur = new ValeurFloat((((ValeurFloat*)vog)->getValeur())/(((ValeurFloat*)vod)->getValeur()));
                else {
                    ErreurDiv(operandeDroit);
                }
            }
            catch (int) {
                throw;
            }
        }
    }
    else if (typeid(*vod) == typeid(ValeurFloat) && typeid(*vog) == typeid(ValeurInt)) {
        if      (this->operateur=="+") valeur = new ValeurFloat((((ValeurInt*)vog)->getValeur())+(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="-") valeur = new ValeurFloat((((ValeurInt*)vog)->getValeur())-(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="*") valeur = new ValeurFloat((((ValeurInt*)vog)->getValeur())*(((ValeurFloat*)vod)->getValeur()));
        else if (this->operateur=="/") {
            try {
                if ((((ValeurInt*)vod)->getValeur())!=0.0 || (*(Symbole*)operandeDroit) == "<VARIABLE>" )
                    valeur = new ValeurFloat((float)(((ValeurInt*)vog)->getValeur())/(((ValeurFloat*)vod)->getValeur()));
                else {
                    ErreurDiv(operandeDroit);
                }
            }
            catch (int) {
                throw;
            }
        }
    }
    if ((this->operateur=="et") || (this->operateur=="ou")) {
        bool bog = 1;
        bool bod = 1;
        if ((typeid(*vog) == typeid(ValeurInt)) && ((((ValeurInt*)vog)->getValeur())==0))
            bog = 0;
        if ((typeid(*vod) == typeid(ValeurInt)) && ((((ValeurInt*)vod)->getValeur())==0))
            bod = 0;
        if ((typeid(*vog) == typeid(ValeurFloat)) && ((((ValeurFloat*)vog)->getValeur())==0.0))
            bog = 0;
        if ((typeid(*vod) == typeid(ValeurFloat)) && ((((ValeurFloat*)vod)->getValeur())==0.0))
            bod = 0;
        if ((typeid(*vog) == typeid(ValeurString)) && ((((ValeurString*)vog)->getValeur())=="'\0'"))
            bog = 0;
        if ((typeid(*vod) == typeid(ValeurString)) && ((((ValeurString*)vod)->getValeur())=="'\0'"))
            bod = 0;
        if ((typeid(*vog) == typeid(ValeurChar)) && ((((ValeurChar*)vog)->getValeur())=='\0'))
            bog = 0;
        if ((typeid(*vod) == typeid(ValeurChar)) && ((((ValeurChar*)vod)->getValeur())=='\0'))
            bog = 0;
        if (this->operateur=="et") {
            if (bog==0) valeur = new ValeurInt(0);
            else {
                if (bod==1) valeur = new ValeurInt(1);
            }
        }
        else { // ou
            if (bog==1) valeur = new ValeurInt(1);
            else {
                if (bod==0) valeur = new ValeurInt(0);
            }
        }
    }

    if (this->operateur=="!") {
        bool bod = 1;
        if ((typeid(*vod) == typeid(ValeurInt)) && ((((ValeurInt*)vod)->getValeur())==0))
            bod = 0;
        if ((typeid(*vod) == typeid(ValeurFloat)) && ((((ValeurFloat*)vod)->getValeur())==0.0))
            bod = 0;
        if ((typeid(*vod) == typeid(ValeurString)) && ((((ValeurString*)vod)->getValeur())=="'\0'"))
            bod = 0;
	if ((typeid(*vod) == typeid(ValeurChar)) && ((((ValeurChar*)vod)->getValeur())=='\0'))
            bod = 0;
        if (bod==1) valeur = new ValeurInt(0);
        else 	valeur = new ValeurInt(1);
    }

    if (typeid(*vog) == typeid(ValeurInt)) {
        if ((this->operateur=="==") && (((ValeurInt*)vog)->getValeur() == ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="!=") && (((ValeurInt*)vog)->getValeur() != ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<=") && (((ValeurInt*)vog)->getValeur() <= ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<") && (((ValeurInt*)vog)->getValeur() < ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">=") && (((ValeurInt*)vog)->getValeur() >= ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">") && (((ValeurInt*)vog)->getValeur() > ((ValeurInt*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
    }
    else if (typeid(*vog) == typeid(ValeurFloat)) {
        if ((this->operateur=="==") && (((ValeurFloat*)vog)->getValeur() == ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="!=") && (((ValeurFloat*)vog)->getValeur() != ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<=") && (((ValeurFloat*)vog)->getValeur() <= ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<") && (((ValeurFloat*)vog)->getValeur() < ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">=") && (((ValeurFloat*)vog)->getValeur() >= ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">") && (((ValeurFloat*)vog)->getValeur() > ((ValeurFloat*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
    }
    else if (typeid(*vog) == typeid(ValeurString)) {
        if ((this->operateur=="==") && (((ValeurString*)vog)->getValeur() == ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="!=") && (((ValeurString*)vog)->getValeur() != ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<=") && (((ValeurString*)vog)->getValeur() <= ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<") && (((ValeurString*)vog)->getValeur() < ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">=") && (((ValeurString*)vog)->getValeur() >= ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">") && (((ValeurString*)vog)->getValeur() > ((ValeurString*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
    }
    else if (typeid(*vog) == typeid(ValeurChar)) {
        if ((this->operateur=="==") && (((ValeurChar*)vog)->getValeur() == ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="!=") && (((ValeurChar*)vog)->getValeur() != ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<=") && (((ValeurChar*)vog)->getValeur() <= ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur=="<") && (((ValeurChar*)vog)->getValeur() < ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">=") && (((ValeurChar*)vog)->getValeur() >= ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
        if ((this->operateur==">") && (((ValeurChar*)vog)->getValeur() > ((ValeurChar*)vod)->getValeur())) {
            valeur = new ValeurInt(1);
        }
    }

    return valeur;
}

void NoeudOperateurBinaire::Accept (NoeudVisitor& visitor) {
    try {
        if (typeid(visitor) == typeid(AfficherVisitor)) {
            visitor.IncresIndentation();
            visitor.VisitNoeudOperateurBinaire(this);
            operandeGauche->Accept(visitor);
            operandeDroit->Accept(visitor);
            visitor.DecresIndentation();
        }
        else if (typeid(visitor) == typeid(ConversionVisitor)) {
            visitor.afficherMotsCles("("); // pour garder la priorité
            operandeGauche->Accept(visitor);
            visitor.afficherOp(operateur.getChaine()) ;
            operandeDroit->Accept(visitor);
            visitor.afficherMotsCles(")");
        }
        else {
            operandeGauche->Accept(visitor);
            operandeDroit->Accept(visitor);
            visitor.VisitNoeudOperateurBinaire(this);
        }
    }
    catch (char const*) {
        throw;
    }
}

void NoeudOperateurBinaire::ErreurDiv (Noeud* op) { // si on divise par 0 affiche une message d'erreur et, leve une exeption
    try {
        cout << endl << "-------- Erreur de division - ligne : " << ((SymboleValue*)op)->getLigne() << endl
             << "   " << "La division par 0 est fortement deconseille "<< " ici : " << ((SymboleValue*)op)->getChaine()  << endl << endl;
        throw "div 0";
    }
    catch (char const*) {
        throw;
    }
}
